﻿use rdev::Key;
use std::fmt;
use std::str::FromStr;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RdevKeyStruct {
    Alt,
    AltGr,
    Backspace,
    CapsLock,
    ControlLeft,
    ControlRight,
    Delete,
    DownArrow,
    End,
    Escape,
    F1,
    F10,
    F11,
    F12,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    Home,
    LeftArrow,
    /// also known as "windows", "super", and "command"
    MetaLeft,
    /// also known as "windows", "super", and "command"
    MetaRight,
    PageDown,
    PageUp,
    Return,
    RightArrow,
    ShiftLeft,
    ShiftRight,
    Space,
    Tab,
    UpArrow,
    PrintScreen,
    ScrollLock,
    Pause,
    NumLock,
    BackQuote,
    Num1,
    Num2,
    Num3,
    Num4,
    Num5,
    Num6,
    Num7,
    Num8,
    Num9,
    Num0,
    Minus,
    Equal,
    KeyQ,
    KeyW,
    KeyE,
    KeyR,
    KeyT,
    KeyY,
    KeyU,
    KeyI,
    KeyO,
    KeyP,
    LeftBracket,
    RightBracket,
    KeyA,
    KeyS,
    KeyD,
    KeyF,
    KeyG,
    KeyH,
    KeyJ,
    KeyK,
    KeyL,
    SemiColon,
    Quote,
    BackSlash,
    IntlBackslash,
    KeyZ,
    KeyX,
    KeyC,
    KeyV,
    KeyB,
    KeyN,
    KeyM,
    Comma,
    Dot,
    Slash,
    Insert,
    KpReturn,
    KpMinus,
    KpPlus,
    KpMultiply,
    KpDivide,
    Kp0,
    Kp1,
    Kp2,
    Kp3,
    Kp4,
    Kp5,
    Kp6,
    Kp7,
    Kp8,
    Kp9,
    KpDelete,
    Function,
    Unknown(u32),
}

impl fmt::Display for RdevKeyStruct {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            RdevKeyStruct::Alt => write!(f, "Alt"),
            RdevKeyStruct::AltGr => write!(f, "AltGr"),
            RdevKeyStruct::Backspace => write!(f, "Backspace"),
            RdevKeyStruct::CapsLock => write!(f, "CapsLock"),
            RdevKeyStruct::ControlLeft => write!(f, "ControlLeft"),
            RdevKeyStruct::ControlRight => write!(f, "ControlRight"),
            RdevKeyStruct::Delete => write!(f, "Delete"),
            RdevKeyStruct::DownArrow => write!(f, "DownArrow"),
            RdevKeyStruct::End => write!(f, "End"),
            RdevKeyStruct::Escape => write!(f, "Escape"),
            RdevKeyStruct::F1 => write!(f, "F1"),
            RdevKeyStruct::F10 => write!(f, "F10"),
            RdevKeyStruct::F11 => write!(f, "F11"),
            RdevKeyStruct::F12 => write!(f, "F12"),
            RdevKeyStruct::F2 => write!(f, "F2"),
            RdevKeyStruct::F3 => write!(f, "F3"),
            RdevKeyStruct::F4 => write!(f, "F4"),
            RdevKeyStruct::F5 => write!(f, "F5"),
            RdevKeyStruct::F6 => write!(f, "F6"),
            RdevKeyStruct::F7 => write!(f, "F7"),
            RdevKeyStruct::F8 => write!(f, "F8"),
            RdevKeyStruct::F9 => write!(f, "F9"),
            RdevKeyStruct::Home => write!(f, "Home"),
            RdevKeyStruct::LeftArrow => write!(f, "LeftArrow"),
            RdevKeyStruct::MetaLeft => write!(f, "MetaLeft"),
            RdevKeyStruct::MetaRight => write!(f, "MetaRight"),
            RdevKeyStruct::PageDown => write!(f, "PageDown"),
            RdevKeyStruct::PageUp => write!(f, "PageUp"),
            RdevKeyStruct::Return => write!(f, "Return"),
            RdevKeyStruct::RightArrow => write!(f, "RightArrow"),
            RdevKeyStruct::ShiftLeft => write!(f, "ShiftLeft"),
            RdevKeyStruct::ShiftRight => write!(f, "ShiftRight"),
            RdevKeyStruct::Space => write!(f, "Space"),
            RdevKeyStruct::Tab => write!(f, "Tab"),
            RdevKeyStruct::UpArrow => write!(f, "UpArrow"),
            RdevKeyStruct::PrintScreen => write!(f, "PrintScreen"),
            RdevKeyStruct::ScrollLock => write!(f, "ScrollLock"),
            RdevKeyStruct::Pause => write!(f, "Pause"),
            RdevKeyStruct::NumLock => write!(f, "NumLock"),
            RdevKeyStruct::BackQuote => write!(f, "BackQuote"),
            RdevKeyStruct::Num1 => write!(f, "Num1"),
            RdevKeyStruct::Num2 => write!(f, "Num2"),
            RdevKeyStruct::Num3 => write!(f, "Num3"),
            RdevKeyStruct::Num4 => write!(f, "Num4"),
            RdevKeyStruct::Num5 => write!(f, "Num5"),
            RdevKeyStruct::Num6 => write!(f, "Num6"),
            RdevKeyStruct::Num7 => write!(f, "Num7"),
            RdevKeyStruct::Num8 => write!(f, "Num8"),
            RdevKeyStruct::Num9 => write!(f, "Num9"),
            RdevKeyStruct::Num0 => write!(f, "Num0"),
            RdevKeyStruct::Minus => write!(f, "Minus"),
            RdevKeyStruct::Equal => write!(f, "Equal"),
            RdevKeyStruct::KeyQ => write!(f, "KeyQ"),
            RdevKeyStruct::KeyW => write!(f, "KeyW"),
            RdevKeyStruct::KeyE => write!(f, "KeyE"),
            RdevKeyStruct::KeyR => write!(f, "KeyR"),
            RdevKeyStruct::KeyT => write!(f, "KeyT"),
            RdevKeyStruct::KeyY => write!(f, "KeyY"),
            RdevKeyStruct::KeyU => write!(f, "KeyU"),
            RdevKeyStruct::KeyI => write!(f, "KeyI"),
            RdevKeyStruct::KeyO => write!(f, "KeyO"),
            RdevKeyStruct::KeyP => write!(f, "KeyP"),
            RdevKeyStruct::LeftBracket => write!(f, "LeftBracket"),
            RdevKeyStruct::RightBracket => write!(f, "RightBracket"),
            RdevKeyStruct::KeyA => write!(f, "KeyA"),
            RdevKeyStruct::KeyS => write!(f, "KeyS"),
            RdevKeyStruct::KeyD => write!(f, "KeyD"),
            RdevKeyStruct::KeyF => write!(f, "KeyF"),
            RdevKeyStruct::KeyG => write!(f, "KeyG"),
            RdevKeyStruct::KeyH => write!(f, "KeyH"),
            RdevKeyStruct::KeyJ => write!(f, "KeyJ"),
            RdevKeyStruct::KeyK => write!(f, "KeyK"),
            RdevKeyStruct::KeyL => write!(f, "KeyL"),
            RdevKeyStruct::SemiColon => write!(f, "SemiColon"),
            RdevKeyStruct::Quote => write!(f, "Quote"),
            RdevKeyStruct::BackSlash => write!(f, "BackSlash"),
            RdevKeyStruct::IntlBackslash => write!(f, "IntlBackslash"),
            RdevKeyStruct::KeyZ => write!(f, "KeyZ"),
            RdevKeyStruct::KeyX => write!(f, "KeyX"),
            RdevKeyStruct::KeyC => write!(f, "KeyC"),
            RdevKeyStruct::KeyV => write!(f, "KeyV"),
            RdevKeyStruct::KeyB => write!(f, "KeyB"),
            RdevKeyStruct::KeyN => write!(f, "KeyN"),
            RdevKeyStruct::KeyM => write!(f, "KeyM"),
            RdevKeyStruct::Comma => write!(f, "Comma"),
            RdevKeyStruct::Dot => write!(f, "Dot"),
            RdevKeyStruct::Slash => write!(f, "Slash"),
            RdevKeyStruct::Insert => write!(f, "Insert"),
            RdevKeyStruct::KpReturn => write!(f, "KpReturn"),
            RdevKeyStruct::KpMinus => write!(f, "KpMinus"),
            RdevKeyStruct::KpPlus => write!(f, "KpPlus"),
            RdevKeyStruct::KpMultiply => write!(f, "KpMultiply"),
            RdevKeyStruct::KpDivide => write!(f, "KpDivide"),
            RdevKeyStruct::Kp0 => write!(f, "Kp0"),
            RdevKeyStruct::Kp1 => write!(f, "Kp1"),
            RdevKeyStruct::Kp2 => write!(f, "Kp2"),
            RdevKeyStruct::Kp3 => write!(f, "Kp3"),
            RdevKeyStruct::Kp4 => write!(f, "Kp4"),
            RdevKeyStruct::Kp5 => write!(f, "Kp5"),
            RdevKeyStruct::Kp6 => write!(f, "Kp6"),
            RdevKeyStruct::Kp7 => write!(f, "Kp7"),
            RdevKeyStruct::Kp8 => write!(f, "Kp8"),
            RdevKeyStruct::Kp9 => write!(f, "Kp9"),
            RdevKeyStruct::KpDelete => write!(f, "KpDelete"),
            RdevKeyStruct::Function => write!(f, "Function"),
            RdevKeyStruct::Unknown(key) => write!(f, "Unknown({})", key),
        }
    }
}

impl FromStr for RdevKeyStruct {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Alt" => Ok(RdevKeyStruct::Alt),
            "AltGr" => Ok(RdevKeyStruct::AltGr),
            "Backspace" => Ok(RdevKeyStruct::Backspace),
            "CapsLock" => Ok(RdevKeyStruct::CapsLock),
            "ControlLeft" => Ok(RdevKeyStruct::ControlLeft),
            "ControlRight" => Ok(RdevKeyStruct::ControlRight),
            "Delete" => Ok(RdevKeyStruct::Delete),
            "DownArrow" => Ok(RdevKeyStruct::DownArrow),
            "End" => Ok(RdevKeyStruct::End),
            "Escape" => Ok(RdevKeyStruct::Escape),
            "F1" => Ok(RdevKeyStruct::F1),
            "F2" => Ok(RdevKeyStruct::F2),
            "F3" => Ok(RdevKeyStruct::F3),
            "F4" => Ok(RdevKeyStruct::F4),
            "F5" => Ok(RdevKeyStruct::F5),
            "F6" => Ok(RdevKeyStruct::F6),
            "F7" => Ok(RdevKeyStruct::F7),
            "F8" => Ok(RdevKeyStruct::F8),
            "F9" => Ok(RdevKeyStruct::F9),
            "F10" => Ok(RdevKeyStruct::F10),
            "F11" => Ok(RdevKeyStruct::F11),
            "F12" => Ok(RdevKeyStruct::F12),
            "Home" => Ok(RdevKeyStruct::Home),
            "LeftArrow" => Ok(RdevKeyStruct::LeftArrow),
            "MetaLeft" => Ok(RdevKeyStruct::MetaLeft),
            "MetaRight" => Ok(RdevKeyStruct::MetaRight),
            "PageDown" => Ok(RdevKeyStruct::PageDown),
            "PageUp" => Ok(RdevKeyStruct::PageUp),
            "Return" => Ok(RdevKeyStruct::Return),
            "RightArrow" => Ok(RdevKeyStruct::RightArrow),
            "ShiftLeft" => Ok(RdevKeyStruct::ShiftLeft),
            "ShiftRight" => Ok(RdevKeyStruct::ShiftRight),
            "Space" => Ok(RdevKeyStruct::Space),
            "Tab" => Ok(RdevKeyStruct::Tab),
            "UpArrow" => Ok(RdevKeyStruct::UpArrow),
            "PrintScreen" => Ok(RdevKeyStruct::PrintScreen),
            "ScrollLock" => Ok(RdevKeyStruct::ScrollLock),
            "Pause" => Ok(RdevKeyStruct::Pause),
            "NumLock" => Ok(RdevKeyStruct::NumLock),
            "BackQuote" => Ok(RdevKeyStruct::BackQuote),
            "Num1" => Ok(RdevKeyStruct::Num1),
            "Num2" => Ok(RdevKeyStruct::Num2),
            "Num3" => Ok(RdevKeyStruct::Num3),
            "Num4" => Ok(RdevKeyStruct::Num4),
            "Num5" => Ok(RdevKeyStruct::Num5),
            "Num6" => Ok(RdevKeyStruct::Num6),
            "Num7" => Ok(RdevKeyStruct::Num7),
            "Num8" => Ok(RdevKeyStruct::Num8),
            "Num9" => Ok(RdevKeyStruct::Num9),
            "Num0" => Ok(RdevKeyStruct::Num0),
            "Minus" => Ok(RdevKeyStruct::Minus),
            "Equal" => Ok(RdevKeyStruct::Equal),
            "KeyQ" => Ok(RdevKeyStruct::KeyQ),
            "KeyW" => Ok(RdevKeyStruct::KeyW),
            "KeyE" => Ok(RdevKeyStruct::KeyE),
            "KeyR" => Ok(RdevKeyStruct::KeyR),
            "KeyT" => Ok(RdevKeyStruct::KeyT),
            "KeyY" => Ok(RdevKeyStruct::KeyY),
            "KeyU" => Ok(RdevKeyStruct::KeyU),
            "KeyI" => Ok(RdevKeyStruct::KeyI),
            "KeyO" => Ok(RdevKeyStruct::KeyO),
            "KeyP" => Ok(RdevKeyStruct::KeyP),
            "LeftBracket" => Ok(RdevKeyStruct::LeftBracket),
            "RightBracket" => Ok(RdevKeyStruct::RightBracket),
            "KeyA" => Ok(RdevKeyStruct::KeyA),
            "KeyS" => Ok(RdevKeyStruct::KeyS),
            "KeyD" => Ok(RdevKeyStruct::KeyD),
            "KeyF" => Ok(RdevKeyStruct::KeyF),
            "KeyG" => Ok(RdevKeyStruct::KeyG),
            "KeyH" => Ok(RdevKeyStruct::KeyH),
            "KeyJ" => Ok(RdevKeyStruct::KeyJ),
            "KeyK" => Ok(RdevKeyStruct::KeyK),
            "KeyL" => Ok(RdevKeyStruct::KeyL),
            "SemiColon" => Ok(RdevKeyStruct::SemiColon),
            "Quote" => Ok(RdevKeyStruct::Quote),
            "BackSlash" => Ok(RdevKeyStruct::BackSlash),
            "IntlBackslash" => Ok(RdevKeyStruct::IntlBackslash),
            "KeyZ" => Ok(RdevKeyStruct::KeyZ),
            "KeyX" => Ok(RdevKeyStruct::KeyX),
            "KeyC" => Ok(RdevKeyStruct::KeyC),
            "KeyV" => Ok(RdevKeyStruct::KeyV),
            "KeyB" => Ok(RdevKeyStruct::KeyB),
            "KeyN" => Ok(RdevKeyStruct::KeyN),
            "KeyM" => Ok(RdevKeyStruct::KeyM),
            "Comma" => Ok(RdevKeyStruct::Comma),
            "Dot" => Ok(RdevKeyStruct::Dot),
            "Slash" => Ok(RdevKeyStruct::Slash),
            "Insert" => Ok(RdevKeyStruct::Insert),
            "KpReturn" => Ok(RdevKeyStruct::KpReturn),
            "KpMinus" => Ok(RdevKeyStruct::KpMinus),
            "KpPlus" => Ok(RdevKeyStruct::KpPlus),
            "KpMultiply" => Ok(RdevKeyStruct::KpMultiply),
            "KpDivide" => Ok(RdevKeyStruct::KpDivide),
            "Kp0" => Ok(RdevKeyStruct::Kp0),
            "Kp1" => Ok(RdevKeyStruct::Kp1),
            "Kp2" => Ok(RdevKeyStruct::Kp2),
            "Kp3" => Ok(RdevKeyStruct::Kp3),
            "Kp4" => Ok(RdevKeyStruct::Kp4),
            "Kp5" => Ok(RdevKeyStruct::Kp5),
            "Kp6" => Ok(RdevKeyStruct::Kp6),
            "Kp7" => Ok(RdevKeyStruct::Kp7),
            "Kp8" => Ok(RdevKeyStruct::Kp8),
            "Kp9" => Ok(RdevKeyStruct::Kp9),
            "KpDelete" => Ok(RdevKeyStruct::KpDelete),
            other if other.starts_with("Unknown(") => {
                let inner = other.trim_start_matches("Unknown(").trim_end_matches(")");
                Ok(RdevKeyStruct::Unknown(inner.to_string().parse().unwrap()))
            }
            _ => Err(()),
        }
    }
}

impl From<Key> for RdevKeyStruct {
    fn from(key: Key) -> Self {
        match key {
            Key::Alt => RdevKeyStruct::Alt,
            Key::AltGr => RdevKeyStruct::AltGr,
            Key::Backspace => RdevKeyStruct::Backspace,
            Key::CapsLock => RdevKeyStruct::CapsLock,
            Key::ControlLeft => RdevKeyStruct::ControlLeft,
            Key::ControlRight => RdevKeyStruct::ControlRight,
            Key::Delete => RdevKeyStruct::Delete,
            Key::DownArrow => RdevKeyStruct::DownArrow,
            Key::End => RdevKeyStruct::End,
            Key::Escape => RdevKeyStruct::Escape,
            Key::F1 => RdevKeyStruct::F1,
            Key::F10 => RdevKeyStruct::F10,
            Key::F11 => RdevKeyStruct::F11,
            Key::F12 => RdevKeyStruct::F12,
            Key::F2 => RdevKeyStruct::F2,
            Key::F3 => RdevKeyStruct::F3,
            Key::F4 => RdevKeyStruct::F4,
            Key::F5 => RdevKeyStruct::F5,
            Key::F6 => RdevKeyStruct::F6,
            Key::F7 => RdevKeyStruct::F7,
            Key::F8 => RdevKeyStruct::F8,
            Key::F9 => RdevKeyStruct::F9,
            Key::Home => RdevKeyStruct::Home,
            Key::LeftArrow => RdevKeyStruct::LeftArrow,
            Key::MetaLeft => RdevKeyStruct::MetaLeft,
            Key::MetaRight => RdevKeyStruct::MetaRight,
            Key::PageDown => RdevKeyStruct::PageDown,
            Key::PageUp => RdevKeyStruct::PageUp,
            Key::Return => RdevKeyStruct::Return,
            Key::RightArrow => RdevKeyStruct::RightArrow,
            Key::ShiftLeft => RdevKeyStruct::ShiftLeft,
            Key::ShiftRight => RdevKeyStruct::ShiftRight,
            Key::Space => RdevKeyStruct::Space,
            Key::Tab => RdevKeyStruct::Tab,
            Key::UpArrow => RdevKeyStruct::UpArrow,
            Key::PrintScreen => RdevKeyStruct::PrintScreen,
            Key::ScrollLock => RdevKeyStruct::ScrollLock,
            Key::Pause => RdevKeyStruct::Pause,
            Key::NumLock => RdevKeyStruct::NumLock,
            Key::BackQuote => RdevKeyStruct::BackQuote,
            Key::Num1 => RdevKeyStruct::Num1,
            Key::Num2 => RdevKeyStruct::Num2,
            Key::Num3 => RdevKeyStruct::Num3,
            Key::Num4 => RdevKeyStruct::Num4,
            Key::Num5 => RdevKeyStruct::Num5,
            Key::Num6 => RdevKeyStruct::Num6,
            Key::Num7 => RdevKeyStruct::Num7,
            Key::Num8 => RdevKeyStruct::Num8,
            Key::Num9 => RdevKeyStruct::Num9,
            Key::Num0 => RdevKeyStruct::Num0,
            Key::Minus => RdevKeyStruct::Minus,
            Key::Equal => RdevKeyStruct::Equal,
            Key::KeyQ => RdevKeyStruct::KeyQ,
            Key::KeyW => RdevKeyStruct::KeyW,
            Key::KeyE => RdevKeyStruct::KeyE,
            Key::KeyR => RdevKeyStruct::KeyR,
            Key::KeyT => RdevKeyStruct::KeyT,
            Key::KeyY => RdevKeyStruct::KeyY,
            Key::KeyU => RdevKeyStruct::KeyU,
            Key::KeyI => RdevKeyStruct::KeyI,
            Key::KeyO => RdevKeyStruct::KeyO,
            Key::KeyP => RdevKeyStruct::KeyP,
            Key::LeftBracket => RdevKeyStruct::LeftBracket,
            Key::RightBracket => RdevKeyStruct::RightBracket,
            Key::KeyA => RdevKeyStruct::KeyA,
            Key::KeyS => RdevKeyStruct::KeyS,
            Key::KeyD => RdevKeyStruct::KeyD,
            Key::KeyF => RdevKeyStruct::KeyF,
            Key::KeyG => RdevKeyStruct::KeyG,
            Key::KeyH => RdevKeyStruct::KeyH,
            Key::KeyJ => RdevKeyStruct::KeyJ,
            Key::KeyK => RdevKeyStruct::KeyK,
            Key::KeyL => RdevKeyStruct::KeyL,
            Key::SemiColon => RdevKeyStruct::SemiColon,
            Key::Quote => RdevKeyStruct::Quote,
            Key::BackSlash => RdevKeyStruct::BackSlash,
            Key::IntlBackslash => RdevKeyStruct::IntlBackslash,
            Key::KeyZ => RdevKeyStruct::KeyZ,
            Key::KeyX => RdevKeyStruct::KeyX,
            Key::KeyC => RdevKeyStruct::KeyC,
            Key::KeyV => RdevKeyStruct::KeyV,
            Key::KeyB => RdevKeyStruct::KeyB,
            Key::KeyN => RdevKeyStruct::KeyN,
            Key::KeyM => RdevKeyStruct::KeyM,
            Key::Comma => RdevKeyStruct::Comma,
            Key::Dot => RdevKeyStruct::Dot,
            Key::Slash => RdevKeyStruct::Slash,
            Key::Insert => RdevKeyStruct::Insert,
            Key::KpReturn => RdevKeyStruct::KpReturn,
            Key::KpMinus => RdevKeyStruct::KpMinus,
            Key::KpPlus => RdevKeyStruct::KpPlus,
            Key::KpMultiply => RdevKeyStruct::KpMultiply,
            Key::KpDivide => RdevKeyStruct::KpDivide,
            Key::Kp0 => RdevKeyStruct::Kp0,
            Key::Kp1 => RdevKeyStruct::Kp1,
            Key::Kp2 => RdevKeyStruct::Kp2,
            Key::Kp3 => RdevKeyStruct::Kp3,
            Key::Kp4 => RdevKeyStruct::Kp4,
            Key::Kp5 => RdevKeyStruct::Kp5,
            Key::Kp6 => RdevKeyStruct::Kp6,
            Key::Kp7 => RdevKeyStruct::Kp7,
            Key::Kp8 => RdevKeyStruct::Kp8,
            Key::Kp9 => RdevKeyStruct::Kp9,
            Key::KpDelete => RdevKeyStruct::KpDelete,
            Key::Function => RdevKeyStruct::Function,
            Key::Unknown(key) => RdevKeyStruct::Unknown(key),
        }
    }
}

impl RdevKeyStruct {
    pub fn to_enigo_key(&self) -> Option<enigo::Key> {
        match self {
            RdevKeyStruct::Alt => Some(enigo::Key::Alt),
            RdevKeyStruct::AltGr => None,
            RdevKeyStruct::Backspace => Some(enigo::Key::Backspace),
            RdevKeyStruct::CapsLock => Some(enigo::Key::CapsLock),
            RdevKeyStruct::ControlLeft => Some(enigo::Key::LControl),
            RdevKeyStruct::ControlRight => Some(enigo::Key::RControl),
            RdevKeyStruct::Delete => Some(enigo::Key::Delete),
            RdevKeyStruct::DownArrow => Some(enigo::Key::DownArrow),
            RdevKeyStruct::End => Some(enigo::Key::End),
            RdevKeyStruct::Escape => Some(enigo::Key::Escape),
            RdevKeyStruct::F1 => Some(enigo::Key::F1),
            RdevKeyStruct::F2 => Some(enigo::Key::F2),
            RdevKeyStruct::F3 => Some(enigo::Key::F3),
            RdevKeyStruct::F4 => Some(enigo::Key::F4),
            RdevKeyStruct::F5 => Some(enigo::Key::F5),
            RdevKeyStruct::F6 => Some(enigo::Key::F6),
            RdevKeyStruct::F7 => Some(enigo::Key::F7),
            RdevKeyStruct::F8 => Some(enigo::Key::F8),
            RdevKeyStruct::F9 => Some(enigo::Key::F9),
            RdevKeyStruct::F10 => Some(enigo::Key::F10),
            RdevKeyStruct::F11 => Some(enigo::Key::F11),
            RdevKeyStruct::F12 => Some(enigo::Key::F12),
            RdevKeyStruct::Home => Some(enigo::Key::Home),
            RdevKeyStruct::LeftArrow => Some(enigo::Key::LeftArrow),
            RdevKeyStruct::MetaLeft => Some(enigo::Key::Meta),
            RdevKeyStruct::MetaRight => Some(enigo::Key::Meta),
            RdevKeyStruct::PageDown => Some(enigo::Key::PageDown),
            RdevKeyStruct::PageUp => Some(enigo::Key::PageUp),
            RdevKeyStruct::RightArrow => Some(enigo::Key::RightArrow),
            RdevKeyStruct::UpArrow => Some(enigo::Key::UpArrow),
            RdevKeyStruct::Return => Some(enigo::Key::Return),
            RdevKeyStruct::Space => Some(enigo::Key::Space),
            RdevKeyStruct::Tab => Some(enigo::Key::Tab),
            RdevKeyStruct::PrintScreen => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::PrintScr);
                #[cfg(target_os = "linux")]
                return Some(enigo::Key::PrintScr);
                #[cfg(target_os = "macos")]
                return None;
            }
            RdevKeyStruct::ScrollLock => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Scroll);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                None
            }
            RdevKeyStruct::Pause => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Pause);
                #[cfg(target_os = "macos")]
                None
            }
            RdevKeyStruct::NumLock => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numlock);
                #[cfg(target_os = "macos")]
                None
            }
            RdevKeyStruct::BackQuote => Some(enigo::Key::Unicode('`')),
            RdevKeyStruct::Num1 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad1);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('1'))
            }
            RdevKeyStruct::Num2 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad2);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('2'))
            }
            RdevKeyStruct::Num3 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad3);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('3'))
            }
            RdevKeyStruct::Num4 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad4);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('4'))
            }
            RdevKeyStruct::Num5 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad5);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('5'))
            }
            RdevKeyStruct::Num6 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad6);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('6'))
            }
            RdevKeyStruct::Num7 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad7);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('7'))
            }
            RdevKeyStruct::Num8 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad8);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('8'))
            }
            RdevKeyStruct::Num9 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad9);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('9'))
            }
            RdevKeyStruct::Num0 => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Numpad0);
                #[cfg(target_os = "macos")]
                Some(enigo::Key::Unicode('0'))
            }
            RdevKeyStruct::Minus => Some(enigo::Key::Unicode('-')),
            RdevKeyStruct::Equal => Some(enigo::Key::Unicode('=')),
            RdevKeyStruct::KeyQ => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Q);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('q'))
            }
            RdevKeyStruct::KeyW => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::W);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('w'))
            }
            RdevKeyStruct::KeyE => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::E);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('e'))
            }
            RdevKeyStruct::KeyR => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::R);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('r'))
            }
            RdevKeyStruct::KeyT => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::T);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('t'))
            }
            RdevKeyStruct::KeyY => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Y);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('y'))
            }
            RdevKeyStruct::KeyU => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::U);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('u'))
            }
            RdevKeyStruct::KeyI => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::I);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('i'))
            }
            RdevKeyStruct::KeyO => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::O);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('o'))
            }
            RdevKeyStruct::KeyP => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::P);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('p'))
            }

            RdevKeyStruct::LeftBracket => Some(enigo::Key::Unicode('[')),
            RdevKeyStruct::RightBracket => Some(enigo::Key::Unicode(']')),
            RdevKeyStruct::KeyA => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::A);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('a'))
            }
            RdevKeyStruct::KeyS => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::S);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('s'))
            }
            RdevKeyStruct::KeyD => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::D);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('d'))
            }
            RdevKeyStruct::KeyF => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::F);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('f'))
            }
            RdevKeyStruct::KeyG => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::G);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('g'))
            }
            RdevKeyStruct::KeyH => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::H);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('h'))
            }
            RdevKeyStruct::KeyJ => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::J);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('j'))
            }
            RdevKeyStruct::KeyK => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::K);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('k'))
            }
            RdevKeyStruct::KeyL => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::L);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('l'))
            }

            RdevKeyStruct::SemiColon => Some(enigo::Key::Unicode(';')),
            RdevKeyStruct::Quote => Some(enigo::Key::Unicode('\'')), //单引号
            RdevKeyStruct::BackSlash => Some(enigo::Key::Unicode('\\')), // 反斜杠
            RdevKeyStruct::IntlBackslash => Some(enigo::Key::Unicode('\\')),
            RdevKeyStruct::KeyZ => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Z);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('z'))
            }
            RdevKeyStruct::KeyX => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::X);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('x'))
            }
            RdevKeyStruct::KeyC => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::C);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('c'))
            }
            RdevKeyStruct::KeyV => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::V);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('v'))
            }
            RdevKeyStruct::KeyB => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::B);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('b'))
            }
            RdevKeyStruct::KeyN => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::N);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('n'))
            }
            RdevKeyStruct::KeyM => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::M);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('m'))
            }

            RdevKeyStruct::Comma => Some(enigo::Key::Unicode(',')),
            RdevKeyStruct::Dot => Some(enigo::Key::Unicode('.')),
            RdevKeyStruct::Slash => Some(enigo::Key::Unicode('/')),
            RdevKeyStruct::Insert => {
                #[cfg(any(target_os = "windows", target_os = "linux"))]
                return Some(enigo::Key::Insert);
                #[cfg(target_os = "macos")]
                None
            }
            RdevKeyStruct::KpReturn => Some(enigo::Key::Return),
            RdevKeyStruct::KpMinus => Some(enigo::Key::Unicode('-')),
            RdevKeyStruct::KpPlus => Some(enigo::Key::Unicode('+')),
            RdevKeyStruct::KpMultiply => Some(enigo::Key::Unicode('*')),
            RdevKeyStruct::KpDivide => Some(enigo::Key::Unicode('/')),
            RdevKeyStruct::Kp0 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num0);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('0'))
            }
            RdevKeyStruct::Kp1 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num1);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('1'))
            }
            RdevKeyStruct::Kp2 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num2);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('2'))
            }
            RdevKeyStruct::Kp3 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num3);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('3'))
            }
            RdevKeyStruct::Kp4 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num4);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('4'))
            }
            RdevKeyStruct::Kp5 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num5);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('5'))
            }
            RdevKeyStruct::Kp6 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num6);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('6'))
            }
            RdevKeyStruct::Kp7 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num7);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('7'))
            }
            RdevKeyStruct::Kp8 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num8);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('8'))
            }
            RdevKeyStruct::Kp9 => {
                #[cfg(target_os = "windows")]
                return Some(enigo::Key::Num9);
                #[cfg(any(target_os = "macos", target_os = "linux"))]
                Some(enigo::Key::Unicode('9'))
            }
            RdevKeyStruct::KpDelete => Some(enigo::Key::Delete),
            RdevKeyStruct::Function => None,
            RdevKeyStruct::Unknown(_) => None,
            RdevKeyStruct::ShiftLeft => Some(enigo::Key::LShift),
            RdevKeyStruct::ShiftRight => Some(enigo::Key::RShift),
        }
    }
}

mod marco {
    #[test]
    fn dry_marco() {
        macro_rules! find_min {
            ($x:expr) => {
                $x
            };
            //$($y:expr), +   匹配多个参数,重复序列
            ($x:expr , $($y:expr), + ) => {{
                {
                    std::cmp::min($x, find_min!($($y),+))
                }
            }};
        }
        let result = find_min!(1, 2, 234, 435);
        assert_eq!(result, 1);

        use std::ops::{Add, Mul, Sub};

        macro_rules! assert_equal_len {
            // `tt`（token tree，标记树）指示符表示运算符和标记。
            ($a:ident, $b: ident, $func:ident, $op:tt) => {
                assert!(
                    $a.len() == $b.len(),
                    "{:?}: dimension mismatch: {:?} {:?} {:?}",
                    stringify!($func),
                    ($a.len(),),
                    stringify!($op),
                    ($b.len(),)
                );
            };
        }

        macro_rules! op {
            ($func:ident, $bound:ident, $op:tt, $method:ident) => {
                fn $func<T: $bound<T, Output = T> + Copy>(xs: &mut Vec<T>, ys: &Vec<T>) {
                    assert_equal_len!(xs, ys, $func, $op);

                    for (x, y) in xs.iter_mut().zip(ys.iter()) {
                        *x = $bound::$method(*x, *y);
                        // *x = x.$method(*y);
                    }
                }
            };
        }

        op!(add_assign, Add, +=, add);
        op!(mul_assign, Mul, *=, mul);
        op!(sub_assign, Sub, -=, sub);

        add_assign(&mut vec![1, 2, 3], &vec![4, 5, 6]);

        mul_assign(&mut vec![1, 2, 3], &vec![4, 5, 6]);

        sub_assign(&mut vec![1, 2, 3], &vec![4, 5, 6]);
    }
}
